home *** CD-ROM | disk | FTP | other *** search
- Subject: v18i090: Elm mail system, release 2.2, Part11/24
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: dsinc!syd@uunet.UU.NET (Syd Weinstein)
- Posting-number: Volume 18, Issue 90
- Archive-name: elm2.2/part11
-
- #!/bin/sh
- # this is part 11 of a multipart archive
- # do not concatenate these parts, unpack them in order with /bin/sh
- # file src/addr_util.c continued
- #
- CurArch=11
- if test ! -r s2_seq_.tmp
- then echo "Please unpack part 1 first!"
- exit 1; fi
- ( read Scheck
- if test "$Scheck" != $CurArch
- then echo "Please unpack part $Scheck next!"
- exit 1;
- else exit 0; fi
- ) < s2_seq_.tmp || exit 1
- echo "x - Continuing file src/addr_util.c"
- sed 's/^X//' << 'SHAR_EOF' >> src/addr_util.c
- X/**
- X get_return_name(address, mail_to, FALSE);
- X**/
- X }
- X
- X bufptr = (char *) NULL; /* set to null */
- X }
- X }
- X
- X return;
- X}
- SHAR_EOF
- echo "File src/addr_util.c is complete"
- chmod 0444 src/addr_util.c || echo "restore of src/addr_util.c fails"
- echo "x - extracting src/alias.c (Text)"
- sed 's/^X//' << 'SHAR_EOF' > src/alias.c &&
- X
- Xstatic char rcsid[] = "@(#)$Id: alias.c,v 2.14 89/03/30 10:25:28 syd Exp $";
- X
- X/*******************************************************************************
- X * The Elm Mail System - $Revision: 2.14 $ $State: Exp $
- X *
- X * Copyright (c) 1986, 1987 Dave Taylor
- X * Copyright (c) 1988, 1989 USENET Community Trust
- X *******************************************************************************
- X * Bug reports, patches, comments, suggestions should be sent to:
- X *
- X * Syd Weinstein, Elm Coordinator
- X * elm@dsinc.UUCP dsinc!elm
- X *
- X *******************************************************************************
- X * $Log: alias.c,v $
- X * Revision 2.14 89/03/30 10:25:28 syd
- X * Check variable value for being in valid range before using to prevent
- X * segmentation violation.
- X * From: Rob Bernardo <rob@pbhyf.PacBell.COM>
- X *
- X * Revision 2.13 89/03/25 21:45:42 syd
- X * Initial 2.2 Release checkin
- X *
- X *
- X ******************************************************************************/
- X
- X/** This file contains alias stuff
- X
- X**/
- X
- X#include "headers.h"
- X#include <errno.h>
- X
- X#ifdef BSD
- X#undef tolower
- X#endif
- X
- X#define ECHOIT 1 /* echo on for prompting */
- X
- Xchar *expand_group(), *get_alias_address(), *expand_system(), *get_token();
- Xchar *error_name(), *error_description(), *strip_parens();
- X
- Xunsigned long sleep();
- X
- Xextern int errno;
- X
- Xextern int findnode_has_been_initialized;
- X
- Xread_alias_files()
- X{
- X /** read the system and user alias files, if present.
- X Set the flags 'systemfiles' and 'userfiles' accordingly.
- X **/
- X
- X char fname[SLEN];
- X int hash;
- X
- X if ((hash = open(system_hash_file, O_RDONLY)) == -1) {
- X dprint(2, (debugfile,
- X "Warning: Can't read system hash file %s\n", system_hash_file));
- X goto user;
- X }
- X
- X read(hash, (char *) system_hash_table, sizeof system_hash_table);
- X close(hash);
- X
- X /* and data file opened.. */
- X
- X if ((system_data = open(system_data_file, O_RDONLY)) == -1) {
- X dprint(1, (debugfile,
- X "Warning: Can't read system data file %s\n", system_data_file));
- X goto user;
- X }
- X
- X system_files++; /* got the system files! */
- X
- Xuser: sprintf(fname, "%s/%s", home, ALIAS_HASH);
- X
- X if ((hash = open(fname, O_RDONLY)) == -1) {
- X dprint(2,(debugfile, "Warning: Can't read user hash file %s\n",
- X fname));
- X return;
- X }
- X
- X read(hash, (char *) user_hash_table, sizeof user_hash_table);
- X close(hash);
- X
- X sprintf(fname, "%s/%s", home, ALIAS_DATA);
- X
- X if ((user_data = open(fname, O_RDONLY)) == -1) {
- X dprint(1, (debugfile,
- X "Warning: can't read user data file %s\n", fname));
- X return;
- X }
- X
- X user_files++; /* got user files too! */
- X}
- X
- Xint
- Xadd_alias()
- X{
- X /** add an alias to the user alias text file. Return zero
- X if alias not added in actuality **/
- X
- X char name[SLEN], *address, address1[LONG_STRING], buffer[LONG_STRING];
- X char comment[SLEN], ch;
- X char *strcpy();
- X
- X strcpy(buffer, "Enter alias name: ");
- X PutLine0(LINES-2,0, buffer);
- X CleartoEOLN();
- X *name = '\0';
- X optionally_enter(name, LINES-2, strlen(buffer), FALSE, FALSE);
- X if (strlen(name) == 0)
- X return(0);
- X if ((address = get_alias_address(name, 0, 0)) != NULL) {
- X dprint(3, (debugfile,
- X "Attempt to add a duplicate alias [%s] in add_alias\n",
- X address));
- X if (address[0] == '!') {
- X address[0] = ' ';
- X error1("Already a group with name %s.", address);
- X }
- X else
- X error1("Already an alias for %s.", address);
- X return(0);
- X }
- X
- X sprintf(buffer, "Enter full name for %s: ", name);
- X PutLine0(LINES-2,0, buffer);
- X CleartoEOLN();
- X *comment = '\0';
- X optionally_enter(comment, LINES-2, strlen(buffer), FALSE, FALSE);
- X if (strlen(comment) == 0) strcpy(comment, name);
- X
- X sprintf(buffer, "Enter address for %s: ", name);
- X PutLine0(LINES-2,0, buffer);
- X CleartoEOLN();
- X *address1 = '\0';
- X optionally_enter(address1, LINES-2, strlen(buffer), FALSE, FALSE);
- X Raw(ON);
- X if (strlen(address1) == 0) {
- X error("No address specified!");
- X return(0);
- X }
- X PutLine3(LINES-2,0,"%s (%s) = %s", comment, name, address1);
- X CleartoEOLN();
- X if((ch = want_to("Accept new alias? (y/n) ",'y')) == 'y')
- X add_to_alias_text(name, comment, address1);
- X ClearLine(LINES-2);
- X return(ch == 'y' ? 1 : 0);
- X}
- X
- Xint
- Xdelete_alias()
- X{
- X /** delete an alias from the user alias text file. Return zero
- X if alias not deleted in actuality **/
- X
- X char name[SLEN], *address, buffer[LONG_STRING];
- X char *strcpy();
- X
- X strcpy(buffer, "Enter alias name for deletion: ");
- X PutLine0(LINES-2,0, buffer);
- X CleartoEOLN();
- X *name = '\0';
- X optionally_enter(name, LINES-2, strlen(buffer), FALSE, FALSE);
- X if (strlen(name) == 0)
- X return(0);
- X if ((address = get_alias_address(name, 0, 0))!=NULL)
- X {
- X if (address[0] == '!')
- X {
- X address[0] = ' ';
- X PutLine1(LINES-1,0,"Group alias: %-60.60s", address);
- X CleartoEOLN();
- X }
- X else
- X PutLine1(LINES-1,0,"Aliased address: %-60.60s", address);
- X }
- X else
- X {
- X dprint(3, (debugfile,
- X "Attempt to delete a non-existent alias [%s] in delete_alias\n",
- X name));
- X error1("No alias for %s.", name);
- X return(0);
- X }
- X if (want_to("Delete this alias? (y/n) ", 'y') == 'y')
- X {
- X if (!delete_from_alias_text(name))
- X {
- X CleartoEOS();
- X return(1);
- X }
- X }
- X CleartoEOS();
- X return(0);
- X}
- X
- Xint
- Xadd_current_alias()
- X{
- X /** alias the current message to the specified name and
- X add it to the alias text file, for processing as
- X the user leaves the program. Returns non-zero iff
- X alias actually added to file **/
- X
- X char name[SLEN], address1[LONG_STRING], buffer[LONG_STRING], *address;
- X char comment[SLEN], ch;
- X struct header_rec *current_header;
- X
- X if (current == 0) {
- X dprint(4, (debugfile,
- X "Add current alias called without any current message!\n"));
- X error("No message to alias to!");
- X return(0);
- X }
- X current_header = headers[current - 1];
- X
- X strcpy(buffer, "Current message address aliased to: ");
- X PutLine0(LINES-2,0, buffer);
- X CleartoEOLN();
- X *name = '\0';
- X optionally_enter(name, LINES-2, strlen(buffer), FALSE, FALSE);
- X if (strlen(name) == 0) /* cancelled... */
- X return(0);
- X if ((address = get_alias_address(name, 0, 0)) != NULL) {
- X dprint(3, (debugfile,
- X "Attempt to add a duplicate alias [%s] in add_current_alias\n",
- X address));
- X if (address[1] == '!') {
- X address[0] = ' ';
- X error1("Already a group with name %s.", address);
- X }
- X else
- X error1("Already an alias for %s.", address);
- X return(0);
- X }
- X
- X sprintf(buffer, "Enter full name for %s: ", name);
- X PutLine0(LINES-2,0, buffer);
- X CleartoEOLN();
- X
- X /* use full name in current message for default comment */
- X tail_of(current_header->from, comment, current_header->to);
- X if(strchr(comment, '!') || strchr(comment, '@'))
- X /* never mind - it's an address not a full name */
- X *comment = '\0';
- X
- X optionally_enter(comment, LINES-2, strlen(buffer), FALSE, FALSE);
- X
- X /* grab the return address of this message */
- X get_return(address1, current-1);
- X
- X /* if this is from the use (a saved copy) use the 'to' addrs instead */
- X get_return_name(address1, buffer, TRUE);
- X if(strcmp(buffer, username) == 0)
- X get_existing_address(address1, current-1);
- X
- X strcpy(address1, strip_parens(address1)); /* remove parens! */
- X#ifdef OPTIMIZE_RETURN
- X optimize_return(address1);
- X#endif
- X PutLine3(LINES-2,0,"%s (%s) = %s", comment, name, address1);
- X CleartoEOLN();
- X if((ch = want_to("Accept new alias? (y/n) ",'y')) == 'y')
- X add_to_alias_text(name, comment, address1);
- X ClearLine(LINES-2);
- X return(ch == 'y' ? 1 : 0);
- X}
- X
- Xadd_to_alias_text(name, comment, address)
- Xchar *name, *comment, *address;
- X{
- X /** Add the data to the user alias text file. Return zero if we
- X succeeded, 1 if not **/
- X
- X FILE *file;
- X char fname[SLEN];
- X
- X sprintf(fname,"%s/%s", home, ALIAS_TEXT);
- X
- X save_file_stats(fname);
- X if ((file = fopen(fname, "a")) == NULL) {
- X dprint(2, (debugfile,
- X "Failure attempting to add alias to file %s within %s",
- X fname, "add_to_alias_text"));
- X dprint(2, (debugfile, "** %s - %s **\n", error_name(errno),
- X error_description(errno)));
- X error1("Couldn't open %s to add new alias!", fname);
- X return(1);
- X }
- X
- X fprintf(file,"%s = %s = %s\n", name, comment, address);
- X fclose(file);
- X
- X restore_file_stats(fname);
- X
- X return(0);
- X}
- X
- Xdelete_from_alias_text(name)
- Xchar *name;
- X{
- X /** Delete the data from the user alias text file. Return zero if we
- X succeeded, 1 if not **/
- X
- X FILE *file, *tmpfile;
- X char fname[SLEN], tmpfname[SLEN];
- X char line_in_file[SLEN+3+SLEN+3+LONG_STRING]; /* name = comment = address */
- X char name_with_equals[SLEN+2];
- X
- X strcpy(name_with_equals, name);
- X strcat(name_with_equals, " =");
- X
- X sprintf(fname,"%s/%s", home, ALIAS_TEXT);
- X sprintf(tmpfname,"%s/%s.tmp", home, ALIAS_TEXT);
- X
- X save_file_stats(fname);
- X
- X if ((file = fopen(fname, "r")) == NULL) {
- X dprint(2, (debugfile,
- X "Failure attempting to delete alias from file %s within %s",
- X fname, "delete_from_alias_text"));
- X dprint(2, (debugfile, "** %s - %s **\n", error_name(errno),
- X error_description(errno)));
- X error1("Couldn't open %s to delete alias!", fname);
- X return(1);
- X }
- X
- X if ((tmpfile = fopen(tmpfname, "w")) == NULL) {
- X dprint(2, (debugfile,
- X "Failure attempting to open temp file %s within %s",
- X tmpfname, "delete_from_alias_text"));
- X dprint(2, (debugfile, "** %s - %s **\n", error_name(errno),
- X error_description(errno)));
- X error1("Couldn't open tempfile %s to delete alias!", tmpfname);
- X return(1);
- X }
- X
- X while (fgets(line_in_file, sizeof(line_in_file), file) != (char *)NULL)
- X {
- X if (strncmp(name_with_equals, line_in_file,
- X strlen(name_with_equals)) != 0)
- X fprintf(tmpfile,"%s", line_in_file);
- X }
- X fclose(file);
- X fclose(tmpfile);
- X if (rename(tmpfname, fname) != 0)
- X {
- X error1("Couldn't rename tempfile %s after deleting alias!", tmpfname);
- X return(1);
- X }
- X
- X restore_file_stats(fname);
- X
- X return(0);
- X}
- X
- Xshow_alias_menu()
- X{
- X MoveCursor(LINES-7,0); CleartoEOS();
- X
- X PutLine0(LINES-7,COLUMNS-45, "Alias commands");
- X Centerline(LINES-6,
- X "a)lias current message, d)elete an alias, check a p)erson or s)ystem,");
- X Centerline(LINES-5,
- X "l)ist existing aliases, m)ake new alias, or r)eturn");
- X}
- X
- Xalias()
- X{
- X /** work with alias commands... **/
- X /** return non-0 if main part of screen overwritten, else 0 **/
- X
- X char name[NLEN], *address, ch, buffer[SLEN];
- X int newaliases = 0, redraw = 0;
- X
- X if (mini_menu)
- X show_alias_menu();
- X
- X /** now let's ensure that we've initialized everything! **/
- X
- X#ifndef DONT_TOUCH_ADDRESSES
- X
- X if (! findnode_has_been_initialized) {
- X if (warnings)
- X error("Initializing internal tables...");
- X#ifndef USE_DBM
- X get_connections();
- X open_domain_file();
- X#endif
- X init_findnode();
- X clear_error();
- X findnode_has_been_initialized = TRUE;
- X }
- X
- X#endif
- X
- X define_softkeys(ALIAS);
- X
- X while (1) {
- X prompt("Alias: ");
- X CleartoEOLN();
- X ch = ReadCh();
- X MoveCursor(LINES-1,0); CleartoEOS();
- X
- X dprint(3, (debugfile, "\n-- Alias command: %c\n\n", ch));
- X
- X switch (tolower(ch)) {
- X case '?': redraw += alias_help(); break;
- X
- X case 'a': newaliases += add_current_alias(); break;
- X case 'd': if (delete_alias()) install_aliases(); break;
- X case 'l': display_aliases();
- X redraw++;
- X if (mini_menu) show_alias_menu();
- X break;
- X case 'm': newaliases += add_alias(); break;
- X
- X case RETURN:
- X case LINE_FEED:
- X case 'q':
- X case 'x':
- X case 'r': if (newaliases) install_aliases();
- X clear_error();
- X return(redraw);
- X case 'p': if (newaliases)
- X error("Warning: new aliases not installed yet!");
- X
- X strcpy(buffer, "Check for person: ");
- X PutLine0(LINES-2,0, buffer);
- X CleartoEOLN();
- X *name = '\0';
- X optionally_enter(name, LINES-2, strlen(buffer),
- X FALSE, FALSE);
- X
- X if ((address = get_alias_address(name, 0, 0))!=NULL) {
- X if (address[0] == '!') {
- X address[0] = ' ';
- X PutLine1(LINES-1,0,"Group alias:%-60.60s", address);
- X CleartoEOLN();
- X }
- X else
- X PutLine1(LINES-1,0,"Aliased address: %-60.60s",
- X address);
- X }
- X else
- X error("Not found.");
- X break;
- X
- X case 's': strcpy(buffer, "Check for system: ");
- X PutLine0(LINES-2,0, buffer);
- X CleartoEOLN();
- X *name = '\0';
- X optionally_enter(name, LINES-2, strlen(buffer),
- X FALSE, FALSE);
- X if (talk_to(name))
- X#ifdef INTERNET
- X PutLine1(LINES-1,0,
- X "You have a direct connection. The address is USER@%s.",
- X name);
- X#else
- X PutLine1(LINES-1,0,
- X "You have a direct connection. The address is %s!USER.",
- X name);
- X#endif
- X else {
- X sprintf(buffer, "USER@%s", name);
- X#ifdef DONT_TOUCH_ADDRESSES
- X address = buffer;
- X#else
- X address = expand_system(buffer, FALSE);
- X#endif
- X if (strlen(address) > strlen(name) + 7)
- X PutLine1(LINES-1,0,"Address is: %.65s", address);
- X else
- X error1("Couldn't expand system %s.", name);
- X }
- X break;
- X
- X case '@': strcpy(buffer, "Fully expand alias: ");
- X PutLine0(LINES-2,0, buffer);
- X CleartoEOS();
- X *name = '\0';
- X optionally_enter(name, LINES-2, strlen(buffer),
- X FALSE, FALSE);
- X if ((address = get_alias_address(name, 1, 0)) != NULL) {
- X ClearScreen();
- X PutLine1(3,0,"Aliased address:\n\r%s", address);
- X PutLine0(LINES-1,0,"Press <return> to continue.");
- X (void) getchar();
- X redraw++;
- X }
- X else
- X error("Not found.");
- X if (mini_menu) show_alias_menu();
- X break;
- X default : error("Invalid input!");
- X }
- X }
- X}
- X
- Xinstall_aliases()
- X{
- X /** run the 'newalias' program and update the
- X aliases before going back to the main program!
- X **/
- X
- X
- X error("Updating aliases...");
- X sleep(2);
- X
- X if (system_call(newalias, SH, FALSE) == 0) {
- X error("Re-reading the database in...");
- X sleep(2);
- X read_alias_files();
- X set_error("Aliases updated successfully.");
- X }
- X else
- X set_error("'Newalias' failed. Please check alias_text.");
- X}
- X
- Xalias_help()
- X{
- X /** help section for the alias menu... **/
- X /** return non-0 if main part of screen overwritten, else 0 */
- X
- X char ch;
- X int redraw=0;
- X
- X MoveCursor(LINES-3, 0); CleartoEOS();
- X
- X if (! mini_menu)
- X lower_prompt("Key you want help for: ");
- X else {
- X Centerline(LINES-3,
- X"Enter key you want help for, '?' for list or '.' to leave help");
- X lower_prompt("Key: ");
- X }
- X
- X while ((ch = ReadCh()) != '.') {
- X ch = tolower(ch);
- X switch(ch) {
- X case '?' : display_helpfile(ALIAS_HELP);
- X redraw++;
- X if (mini_menu) show_alias_menu();
- X return(redraw);
- X case 'a': error(
- X "a = Add (return) address of current message to alias database.");
- X break;
- X case 'd': error("d = Delete a user alias from alias database.");
- X break;
- X case 'l': error("l = List all aliases in database.");
- X break;
- X case 'm': error(
- X "m = Make a new user alias, adding to alias database when done.");
- X break;
- X
- X case RETURN:
- X case LINE_FEED:
- X case 'q':
- X case 'x':
- X case 'r': error("Return from alias menu.");
- X break;
- X
- X case 'p': error("p = Check for a person in the alias database.");
- X break;
- X
- X case 's': error(
- X "s = Check for a system in the host routing/domain database.");
- X break;
- X
- X default : error("That key isn't used in this section.");
- X break;
- X }
- X if (! mini_menu)
- X lower_prompt("Key you want help for: ");
- X else
- X lower_prompt("Key: ");
- X }
- X return(redraw);
- X}
- X
- Xdisplay_aliases()
- X{
- X char fname[SLEN];
- X
- X sprintf(fname,"%s/%s", home, ALIAS_TEXT);
- X display_file(fname);
- X ClearScreen();
- X return;
- X}
- SHAR_EOF
- chmod 0444 src/alias.c || echo "restore of src/alias.c fails"
- echo "x - extracting src/aliasdb.c (Text)"
- sed 's/^X//' << 'SHAR_EOF' > src/aliasdb.c &&
- X
- Xstatic char rcsid[] = "@(#)$Id: aliasdb.c,v 2.8 89/03/25 21:45:45 syd Exp $";
- X
- X/*******************************************************************************
- X * The Elm Mail System - $Revision: 2.8 $ $State: Exp $
- X *
- X * Copyright (c) 1986, 1987 Dave Taylor
- X * Copyright (c) 1988, 1989 USENET Community Trust
- X *******************************************************************************
- X * Bug reports, patches, comments, suggestions should be sent to:
- X *
- X * Syd Weinstein, Elm Coordinator
- X * elm@dsinc.UUCP dsinc!elm
- X *
- X *******************************************************************************
- X * $Log: aliasdb.c,v $
- X * Revision 2.8 89/03/25 21:45:45 syd
- X * Initial 2.2 Release checkin
- X *
- X *
- X ******************************************************************************/
- X
- X/** Alias database files...
- X
- X**/
- X
- X
- X#include "headers.h"
- X
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include <errno.h>
- X
- Xextern int errno;
- X
- X#ifdef USE_DBM
- X# include <dbm.h>
- X#endif
- X
- X#define absolute(x) ((x) > 0 ? x : -(x))
- X
- Xchar *shift_lower(), *find_path_to(), *strcat(), *strcpy();
- Xunsigned long sleep();
- X
- Xint findnode_has_been_initialized = FALSE;
- X
- Xfindnode(name, display_error)
- Xchar *name;
- Xint display_error;
- X{
- X /** break 'name' into machine!user or user@machine and then
- X see if you can find 'machine' in the path database..
- X If so, return name as the expanded address. If not,
- X return what was given to us! If display_error, then
- X do so...
- X **/
- X
- X#ifndef DONT_TOUCH_ADDRESSES
- X
- X char old_name[SLEN];
- X char address[SLEN];
- X
- X if (strlen(name) == 0)
- X return;
- X
- X if (! findnode_has_been_initialized) {
- X if (warnings)
- X error("Initializing internal tables...");
- X#ifndef USE_DBM
- X get_connections();
- X open_domain_file();
- X#endif
- X init_findnode();
- X clear_error();
- X findnode_has_been_initialized = TRUE;
- X }
- X
- X strcpy(old_name, name); /* save what we were given */
- X
- X if (expand_site(name, address) == -1) {
- X if (display_error && name[0] != '!') {
- X dprint(3, (debugfile, "Couldn't expand host %s in address.\n",
- X name));
- X if (! check_only && warnings) {
- X error1("Couldn't expand system %s.", name);
- X sleep(1);
- X }
- X }
- X strcpy(name, old_name); /* and restore... */
- X }
- X else
- X strcpy(name, address);
- X#endif
- X return;
- X}
- X
- Xint
- Xexpand_site(cryptic, expanded)
- Xchar *cryptic, *expanded;
- X{
- X
- X /** Given an address of the form 'xyz@site' or 'site!xyz'
- X return an address of the form <expanded address for site>
- X with 'xyz' embedded according to the path database entry.
- X Note that 'xyz' can be eiher a simple address (as in "joe")
- X or a complex address (as in "joe%xerox.parc@Xerox.ARPA")!
- X 0 = found, -1 return means unknown site code
- X
- X Modified to strip out parenthetical comments...
- X **/
- X
- X#ifdef ACSNET
- X
- X strcpy(expanded, cryptic); /* fast and simple */
- X return(0);
- X
- X#else
- X# ifdef USE_DBM
- X datum key, contents;
- X# endif
- X
- X char name[VERY_LONG_STRING], sitename[VERY_LONG_STRING],
- X temp[VERY_LONG_STRING], old_name[VERY_LONG_STRING],
- X comment[LONG_STRING];
- X char *expand_domain(), *addr;
- X register int i = 0, j = 0, in_parens = 0, domain_name;
- X
- X strcpy(old_name, cryptic); /* remember what we were given */
- X
- X /** break down **/
- X
- X /** first, rip out the comment, if any, noting nested parens **/
- X
- X if ((i = chloc(cryptic, '(')) > -1) {
- X comment[j++] = ' '; /* leading space */
- X do {
- X switch(comment[j++] = cryptic[i++]) {
- X case '(': in_parens++;
- X break;
- X case ')': in_parens--;
- X break;
- X }
- X } while(in_parens && cryptic[i] != '\0');
- X comment[j] = '\0';
- X
- X /* and remove this from cryptic string too... */
- X if (cryptic[(j = chloc(cryptic,'('))-1] == ' ')
- X cryptic[j-1] = '\0';
- X else
- X cryptic[j] = '\0';
- X }
- X else
- X comment[0] = '\0';
- X
- X i = j = 0; /* reset */
- X
- X while (cryptic[i] != AT_SIGN && cryptic[i] != BANG &&
- X cryptic[i] != '\0' && cryptic[i] != '(')
- X sitename[j++] = cryptic[i++];
- X
- X sitename[j++] = '\0';
- X
- X j = 0;
- X
- X if (cryptic[i] == '\0') return(-1); /* nothing to expand! */
- X
- X domain_name = (cryptic[i] == AT_SIGN);
- X
- X i++;
- X
- X while (cryptic[i] != '\0' && cryptic[i] != '(' &&
- X ! whitespace(cryptic[i]))
- X name[j++] = cryptic[i++];
- X
- X name[j] = '\0';
- X
- X if (domain_name) {
- X strcpy(temp, name);
- X strcpy(name, sitename);
- X strcpy(sitename, temp);
- X }
- X
- X dprint(5, (debugfile, "\nBroke address into '%s' @ '%s' '%s'\n\n",
- X name, sitename, comment));
- X
- X#ifdef USE_DBM
- X
- X if (size_of_pathfd == 0)
- X return(-1);
- X
- X key.dptr = sitename;
- X key.dsize = strlen(sitename) + 1;
- X
- X contents = fetch(key);
- X
- X if (contents.dptr == 0)
- X return(-1); /* can't find it! */
- X
- X sprintf(expanded, contents.dptr, name);
- X strcat(expanded, " "); /* add a single space... */
- X strcat(expanded, comment); /* ...and add comment */
- X return(0);
- X#endif
- X
- X#ifndef LOOK_CLOSE_AFTER_SEARCH
- X
- X if (talk_to(sitename)) {
- X strcpy(expanded, old_name); /* restore! */
- X return(0);
- X }
- X#endif
- X
- X if ((addr = find_path_to(sitename, TRUE)) == NULL) {
- X
- X#ifdef LOOK_CLOSE_AFTER_SEARCH
- X
- X if (talk_to(sitename)) {
- X strcpy(expanded, old_name); /* restore! */
- X return(0);
- X }
- X else
- X#endif
- X if ((addr = expand_domain(cryptic)) != NULL) {
- X strcpy(expanded, addr); /* into THIS buffer */
- X strcat(expanded, comment); /* patch in comment */
- X return(0);
- X }
- X else if (size_of_pathfd == 0) { /* no path database! */
- X strcpy(expanded, old_name); /* restore! */
- X return(0);
- X }
- X else { /* We just can't get there! */
- X strcpy(expanded, old_name); /* restore! */
- X return(-1);
- X }
- X }
- X else { /* search succeeded */
- X sprintf(expanded, addr, name);
- X strcat(expanded, comment); /* add comment */
- X return(0);
- X }
- X#endif
- X}
- X
- Xint
- Xbinary_search(name, address)
- Xchar *name, *address;
- X{
- X /* binary search file for name. Return 0 if found, -1 if not */
- X
- X char machine[40];
- X register long first = 0, last, middle;
- X register int compare;
- X
- X address[0] = '\0';
- X
- X last = size_of_pathfd;
- X
- X do {
- X
- X middle = (long) ((first+last) / 2);
- X
- X get_entry(machine, address, pathfd, middle);
- X
- X compare = strcmp(name, machine);
- X
- X if (compare < 0)
- X last = middle - 1;
- X else if (compare == 0)
- X return(0);
- X else /* greater */
- X first = middle + 1;
- X } while (absolute(last) - absolute(first) > FIND_DELTA);
- X
- X /* It could be that our target entry lies exactly at `first'.
- X * Since get_entry() compares at the entry beginning after
- X * the passed offset (unless it's 0), we need to decrement it
- X * (unless it's 0), and give it one more try.
- X */
- X get_entry(machine, address, pathfd, (first == 0L ? first : --first));
- X compare = strcmp(name, machine);
- X return(compare == 0 ? 0 : -1);
- X}
- X
- Xget_entry(machine, address, fileid, offset)
- Xchar *machine, *address;
- XFILE *fileid;
- Xlong offset;
- X{
- X /** get entry...return machine and address immediately
- X following given offset in fileid. **/
- X
- X (void) fseek(fileid, offset, 0);
- X
- X /* To get to the beginning of a record, if we are not at offset 0,
- X * read until we hit an end-of-line */
- X
- X if(offset != 0L)
- X while (getc(fileid) != '\n')
- X ;
- X
- X fscanf(fileid, "%s\t%s", machine, address);
- X}
- X
- Xinit_findnode()
- X{
- X /** Initialize the FILE and 'size_of_file' values for the
- X findnode procedure **/
- X
- X struct stat buffer;
- X char *path_filename;
- X
- X#ifdef USE_DBM
- X char buf[BUFSIZ];
- X
- X sprintf(buf,"%s.pag", pathfile);
- X path_filename = buf;
- X#else
- X path_filename = pathfile;
- X#endif
- X
- X if (stat(path_filename, &buffer) == -1) {
- X dprint(2, (debugfile,
- X "Warning: pathalias file \"%s\" wasn't found by %s\n",
- X path_filename, "init_findnode"));
- X size_of_pathfd = 0;
- X return;
- X }
- X
- X size_of_pathfd = (long) buffer.st_size;
- X
- X#ifdef USE_DBM
- X
- X if (dbminit(pathfile) != 0) {
- X dprint(2, (debugfile,
- X "Warning: couldn't initialize DBM database %s\n",
- X pathfile));
- X dprint(2, (debugfile, "** %s - %s **\n\n", error_name(errno),
- X error_description(errno)));
- X size_of_pathfd = 0; /* error flag, in this case */
- X return;
- X }
- X
- X return;
- X#else
- X
- X if ((pathfd = fopen(pathfile,"r")) == NULL) {
- X dprint(2, (debugfile,
- X "Warning: Can't read pathalias file \"%s\" within %s\n",
- X pathfile, "init_findnode"));
- X size_of_pathfd = 0;
- X }
- X else
- X dprint(3, (debugfile, "\nOpened '%s' as pathalias database.\n\n",
- X pathfile));
- X#endif
- X}
- X
- Xchar *find_path_to(machine, printf_format)
- Xchar *machine;
- Xint printf_format;
- X{
- X /** Returns either the path to the specified machine or NULL if
- X not found. If "printf_format" is TRUE, then it leaves the
- X '%s' intact, otherwise it assumes that the address is a uucp
- X address for the domain expansion program and removes the
- X last three characters of the expanded name ("!%s") since
- X they're redundant with the expansion!
- X **/
- X
- X static char buffer[SLEN]; /* space for path */
- X
- X if (size_of_pathfd > 0)
- X if (binary_search(machine, buffer) != -1) { /* found it! */
- X if (! printf_format && strlen(buffer) > 3)
- X buffer[strlen(buffer)-3] = '\0';
- X return( (char *) buffer);
- X }
- X
- X return(NULL); /* failed if it's here! */
- X}
- SHAR_EOF
- chmod 0444 src/aliasdb.c || echo "restore of src/aliasdb.c fails"
- echo "x - extracting src/aliaslib.c (Text)"
- sed 's/^X//' << 'SHAR_EOF' > src/aliaslib.c &&
- X
- Xstatic char rcsid[] = "@(#)$Id: aliaslib.c,v 2.5 89/03/25 21:45:46 syd Exp $";
- X
- X/*******************************************************************************
- X * The Elm Mail System - $Revision: 2.5 $ $State: Exp $
- X *
- X * Copyright (c) 1986, 1987 Dave Taylor
- X * Copyright (c) 1988, 1989 USENET Community Trust
- X *******************************************************************************
- X * Bug reports, patches, comments, suggestions should be sent to:
- X *
- X * Syd Weinstein, Elm Coordinator
- X * elm@dsinc.UUCP dsinc!elm
- X *
- X *******************************************************************************
- X * $Log: aliaslib.c,v $
- X * Revision 2.5 89/03/25 21:45:46 syd
- X * Initial 2.2 Release checkin
- X *
- X *
- X ******************************************************************************/
- X
- X/** Library of functions dealing with the alias system...
- X
- X **/
- X
- X#include "headers.h"
- X
- Xchar *expand_group(), *get_alias_address(), *expand_system();
- Xchar *get_token(), *strpbrk();
- Xlong lseek();
- X
- Xchar *get_alias_address(name, mailing, depth)
- Xchar *name;
- Xint mailing, depth;
- X{
- X /** return the line from either datafile that corresponds
- X to the specified name. If 'mailing' specified, then
- X fully expand group names. Depth specifies the nesting
- X depth - the routine should always initially be called
- X with this equal 0. Returns NULL if not found **/
- X
- X static char buffer[VERY_LONG_STRING];
- X int loc;
- X
- X if (strlen(name) == 0)
- X return( (char *) NULL);
- X
- X if (! read_in_aliases) {
- X read_alias_files();
- X read_in_aliases = TRUE;
- X }
- X
- X if (user_files)
- X if ((loc = find(name, user_hash_table, MAX_UALIASES)) >= 0) {
- X lseek(user_data, user_hash_table[loc].byte, 0L);
- X get_line(user_data, buffer);
- X if (buffer[0] == '!' && mailing)
- X return(expand_group(buffer, depth));
- X else if (strpbrk(buffer,"!@:") != NULL) /* has a hostname */
- X#ifdef DONT_TOUCH_ADDRESSES
- X return((char *) buffer);
- X#else
- X return(expand_system(buffer, TRUE));
- X#endif
- X else
- X return((char *) buffer);
- X }
- X
- X if (system_files)
- X if ((loc = find(name, system_hash_table, MAX_SALIASES)) >= 0) {
- X lseek(system_data, system_hash_table[loc].byte, 0L);
- X get_line(system_data, buffer);
- X if (buffer[0] == '!' && mailing)
- X return(expand_group(buffer, depth));
- X else if (strpbrk(buffer,"!@:") != NULL) /* has a hostname */
- X#ifdef DONT_TOUCH_ADDRESSES
- X return((char *) buffer);
- X#else
- X return(expand_system(buffer, TRUE));
- X#endif
- X else
- X return((char *) buffer);
- X }
- X
- X return( (char *) NULL);
- X}
- X
- Xchar *expand_system(buffer, show_errors)
- Xchar *buffer;
- Xint show_errors;
- X{
- X /** This routine will check the first machine name in the given path
- X (if any) and expand it out if it is an alias...if not, it will
- X return what it was given. If show_errors is false, it won't
- X display errors encountered...
- X **/
- X
- X dprint(6, (debugfile, "expand_system(%s, show-errors=%s)\n", buffer,
- X onoff(show_errors)));
- X findnode(buffer, show_errors);
- X
- X return( (char *) buffer);
- X}
- X
- Xchar *expand_group(members, depth)
- Xchar *members;
- Xint depth;
- X{
- X /** Given a group of names separated by commas, this routine
- X will return a string that is the full addresses of each
- X member separated by spaces. Depth is an internal counter
- X that keeps track of the depth of nesting that the routine
- X is in...it's for the get_token routine! **/
- X
- X static char buffer[VERY_LONG_STRING];
- X char buf[LONG_STRING], *word, *address, *bufptr;
- X char *strcpy();
- X
- X strcpy(buf, members); /* parameter safety! */
- X if (depth == 0) buffer[0] = '\0'; /* nothing in yet! */
- X bufptr = (char *) buf; /* grab the address */
- X depth++; /* one deeper! */
- X
- X while ((word = get_token(bufptr, "!, ", depth)) != NULL) {
- X if ((address = get_alias_address(word, 1, depth)) == NULL) {
- X if (! valid_name(word)) {
- X dprint(3, (debugfile, "Encountered illegal address %s in %s\n",
- X word, "expand_group"));
- X error1("%s is an illegal address!", word);
- X return( (char *) NULL);
- X }
- X else if (strcmp(buffer, word) != 0)
- X sprintf(buffer, "%s%s%s", buffer,
- X (strlen(buffer) > 0)? ", ":"", word);
- X }
- X else if (strcmp(buffer, address) != 0)
- X sprintf(buffer,"%s%s%s", buffer,
- X (strlen(buffer) > 0)? ", ":"", address);
- X
- X bufptr = NULL;
- X }
- X
- X return( (char *) buffer);
- X}
- X
- Xint
- Xfind(word, table, size)
- Xchar *word;
- Xstruct alias_rec table[];
- Xint size;
- X{
- X /** find word and return loc, or -1 **/
- X register int loc;
- X
- X if (strlen(word) > 20) {
- X dprint(3, (debugfile, "Overly long alias name entered: %s\n", word));
- X error1("Bad alias name: %s. Too long.\n", word);
- X return(-1);
- X }
- X
- X loc = hash_it(word, size);
- X
- X while (strcmp(word, table[loc].name) != 0) {
- X if (table[loc].name[0] == '\0')
- X return(-1);
- X loc = (loc + 1) % size;
- X }
- X
- X return(loc);
- X}
- X
- Xint
- Xhash_it(string, table_size)
- Xchar *string;
- Xint table_size;
- X{
- X /** compute the hash function of the string, returning
- X it (mod table_size) **/
- X
- X register int i, sum = 0;
- X
- X for (i=0; string[i] != '\0'; i++)
- X sum += (int) string[i];
- X
- X return(sum % table_size);
- X}
- X
- Xget_line(fd, buffer)
- Xint fd;
- Xchar *buffer;
- X{
- X /* Read from file fd. End read upon reading either
- X EOF or '\n' character (this is where it differs
- X from a straight 'read' command!) */
- X
- X register int i= 0;
- X char ch;
- X
- X while (read(fd, &ch, 1) > 0)
- X if (ch == '\n' || ch == '\r') {
- X buffer[i] = 0;
- X return;
- X }
- X else
- X buffer[i++] = ch;
- X}
- SHAR_EOF
- chmod 0444 src/aliaslib.c || echo "restore of src/aliaslib.c fails"
- echo "x - extracting src/args.c (Text)"
- sed 's/^X//' << 'SHAR_EOF' > src/args.c &&
- X
- Xstatic char rcsid[] = "@(#)$Id: args.c,v 2.9 89/03/25 21:45:48 syd Exp $";
- X
- X/*******************************************************************************
- X * The Elm Mail System - $Revision: 2.9 $ $State: Exp $
- X *
- X * Copyright (c) 1986, 1987 Dave Taylor
- X * Copyright (c) 1988, 1989 USENET Community Trust
- X *******************************************************************************
- X * Bug reports, patches, comments, suggestions should be sent to:
- X *
- X * Syd Weinstein, Elm Coordinator
- X * elm@dsinc.UUCP dsinc!elm
- X *
- X *******************************************************************************
- X * $Log: args.c,v $
- X * Revision 2.9 89/03/25 21:45:48 syd
- X * Initial 2.2 Release checkin
- X *
- X *
- X ******************************************************************************/
- X
- X/** starting argument parsing routines for ELM system...
- X
- X**/
- X
- X#include "headers.h"
- X
- X
- Xextern char *optarg; /* optional argument as we go */
- Xextern int optind; /* argnum + 1 when we leave */
- X
- Xvoid exit(); /* just keeping lint happy.... */
- X
- Xchar *
- Xparse_arguments(argc, argv, to_whom)
- Xint argc;
- Xchar *argv[], *to_whom;
- X{
- X /** Set flags according to what was given to program. If we are
- X fed a name or series of names, put them into the 'to_whom' buffer
- X and if the check_only flag wasn't presented, set mail_only to ON,
- X and if stdin is not a tty, set batch_only to ON;
- X Return req_mfile, which points to a named mail file or is empty.
- X **/
- X
- X register int c = 0;
- X char *strcpy();
- X static char req_mfile[SLEN];
- X
- X to_whom[0] = '\0';
- X batch_subject[0] = '\0';
- X
- X while ((c = getopt(argc, argv, "?acd:f:hkKms:Vwz")) != EOF) {
- X switch (c) {
- X case 'a' : arrow_cursor++; break;
- X case 'c' : check_only++; break;
- X case 'd' : debug = atoi(optarg); break;
- X case 'f' : strcpy(req_mfile, optarg); break;
- X case '?' :
- X case 'h' : args_help();
- X case 'k' : hp_terminal++; break;
- X case 'K' : hp_terminal++; hp_softkeys++; break;
- X case 'm' : mini_menu = 0; break;
- X case 's' : strcpy(batch_subject, optarg); break;
- X case 'V' : sendmail_verbose++; break;
- X case 'w' : warnings = 0; break;
- X case 'z' : check_size++; break;
- X }
- X }
- X
- X
- X#ifndef DEBUG
- X if (debug)
- X printf(
- X "Warning: system created without debugging enabled - request ignored\n");
- X debug = 0;
- X#endif
- X
- X if (optind < argc) {
- X while (optind < argc) {
- X if (strlen(to_whom) + strlen(to_whom[0] != '\0'? " " : "") +
- X strlen(argv[optind]) > SLEN)
- X exit(printf("\n\rToo many addresses, or addresses too long!\n\r"));
- X
- X sprintf(to_whom, "%s%s%s", to_whom,
- X to_whom[0] != '\0'? " " : "", argv[optind]);
- X if(!check_only)
- X mail_only++;
- X optind++;
- X }
- X check_size = 0; /* NEVER do this if we're mailing!! */
- X }
- X
- X if (strlen(batch_subject) > 0 && ! mail_only)
- X exit(printf(
- X "\n\rDon't understand specifying a subject and no-one to send to!\n\r"));
- X
- X if (!isatty(fileno(stdin)) && !check_only) {
- X batch_only = ON;
- X if(*batch_subject == '\0')
- X strcpy(batch_subject, DEFAULT_BATCH_SUBJECT);
- X }
- X return(req_mfile);
- X
- X
- X}
- X
- Xargs_help()
- X{
- X /** print out possible starting arguments... **/
- X
- X printf("\nPossible Starting Arguments for ELM program:\n\n");
- X printf("\targ\t\t\tMeaning\n");
- X printf("\t -a \t\tArrow - use the arrow pointer regardless\n");
- X printf("\t -c \t\tCheckalias - check the given aliases only\n");
- X printf("\t -dn\t\tDebug - set debug level to 'n'\n");
- X printf(
- X "\t -fx\t\tFolder - read folder 'x' rather than incoming mailbox\n");
- X printf("\t -h \t\tHelp - give this list of options\n");
- X printf("\t -k \t\tKeypad - enable HP 2622 terminal keyboard\n");
- X printf("\t -K \t\tKeypad&softkeys - enable use of softkeys + \"-k\"\n");
- X printf("\t -m \t\tMenu - Turn off menu, using more of the screen\n");
- X printf("\t -sx\t\tSubject 'x' - for batchmailing\n");
- X printf("\t -V \t\tEnable sendmail voyeur mode.\n");
- X printf("\t -w \t\tSupress warning messages...\n");
- X printf("\t -z \t\tZero - don't enter ELM if no mail is pending\n");
- X printf("\n");
- X printf("\n");
- X exit(1);
- X}
- SHAR_EOF
- chmod 0444 src/args.c || echo "restore of src/args.c fails"
- echo "x - extracting src/bouncebk.c (Text)"
- sed 's/^X//' << 'SHAR_EOF' > src/bouncebk.c &&
- X
- Xstatic char rcsid[] = "@(#)$Id: bouncebk.c,v 2.3 89/03/25 21:45:49 syd Exp $";
- X
- X/*******************************************************************************
- X * The Elm Mail System - $Revision: 2.3 $ $State: Exp $
- X *
- X * Copyright (c) 1986, 1987 Dave Taylor
- X * Copyright (c) 1988, 1989 USENET Community Trust
- X *******************************************************************************
- X * Bug reports, patches, comments, suggestions should be sent to:
- X *
- X * Syd Weinstein, Elm Coordinator
- X * elm@dsinc.UUCP dsinc!elm
- X *
- X *******************************************************************************
- X * $Log: bouncebk.c,v $
- X * Revision 2.3 89/03/25 21:45:49 syd
- X * Initial 2.2 Release checkin
- X *
- X *
- X ******************************************************************************/
- X
- X/** This set of routines implement the bounceback feature of the mailer.
- X This feature allows mail greater than 'n' hops away (n specified by
- X the user) to have a 'cc' to the user through the remote machine.
- X
- X Due to the vagaries of the Internet addressing (uucp -> internet -> uucp)
- X this will NOT generate bounceback copies with mail to an internet host!
- X
- X**/
- X
- X#include "headers.h"
- X
- Xchar *bounce_off_remote(), /* forward declaration */
- X *strcat(), *strcpy();
- X
- Xint
- Xuucp_hops(to)
- Xchar *to;
- X{
- X /** Given the entire "To:" list, return the number of hops in the
- X first address (a hop = a '!') or ZERO iff the address is to a
- X non uucp address.
- X **/
- X
- X register int hopcount = 0, iindex;
- X
- X for (iindex = 0; ! whitespace(to[iindex]) && to[iindex] != '\0'; iindex++) {
- X if (to[iindex] == '!')
- X hopcount++;
- X else if (to[iindex] == '@' || to[iindex] == '%' || to[iindex] == ':')
- X return(0); /* don't continue! */
- X }
- X
- X return(hopcount);
- X}
- X
- Xchar *bounce_off_remote(to)
- Xchar *to;
- X{
- X /** Return an address suitable for framing (no, that's not it...)
- X Er, suitable for including in a 'cc' line so that it ends up
- X with the bounceback address. The method is to take the first
- X address in the To: entry and break it into machines, then
- X build a message up from that. For example, consider the
- X following address:
- X a!b!c!d!e!joe
- X the bounceback address would be;
- X a!b!c!d!e!d!c!b!a!ourmachine!ourname
- X simple, eh?
- X **/
- X
- X static char address[LONG_STRING]; /* BEEG address buffer! */
- X
- X char host[MAX_HOPS][NLEN]; /* for breaking up addr */
- X register int hostcount = 0, hindex = 0,
- X iindex;
- X
- X for (iindex = 0; !whitespace(to[iindex]) && to[iindex] != '\0'; iindex++) {
- X if (to[iindex] == '!') {
- X host[hostcount][hindex] = '\0';
- X hostcount++;
- X hindex = 0;
- X }
- X else
- X host[hostcount][hindex++] = to[iindex];
- X }
- X
- X /* we have hostcount hosts... */
- X
- X strcpy(address, host[0]); /* initialize it! */
- X
- X for (iindex=1; iindex < hostcount; iindex++) {
- X strcat(address, "!");
- X strcat(address, host[iindex]);
- X }
- X
- X /* and now the same thing backwards... */
- X
- X for (iindex = hostcount -2; iindex > -1; iindex--) {
- X strcat(address, "!");
- X strcat(address, host[iindex]);
- X }
- X
- X /* and finally, let's tack on our machine and login name */
- X
- X strcat(address, "!");
- X strcat(address, hostname);
- X strcat(address, "!");
- X strcat(address, username);
- X
- X /* and we're done!! */
- X
- X return( (char *) address );
- X}
- SHAR_EOF
- chmod 0444 src/bouncebk.c || echo "restore of src/bouncebk.c fails"
- echo "x - extracting src/builtin.c (Text)"
- sed 's/^X//' << 'SHAR_EOF' > src/builtin.c &&
- X
- Xstatic char rcsid[] = "@(#)$Id: builtin.c,v 2.23 89/03/25 21:45:51 syd Exp $";
- X
- X/*******************************************************************************
- X * The Elm Mail System - $Revision: 2.23 $ $State: Exp $
- X *
- X * Copyright (c) 1986, 1987 Dave Taylor
- X * Copyright (c) 1988, 1989 USENET Community Trust
- X *******************************************************************************
- X * Bug reports, patches, comments, suggestions should be sent to:
- X *
- X * Syd Weinstein, Elm Coordinator
- X * elm@dsinc.UUCP dsinc!elm
- X *
- X *******************************************************************************
- X * $Log: builtin.c,v $
- X * Revision 2.23 89/03/25 21:45:51 syd
- X * Initial 2.2 Release checkin
- X *
- X *
- X ******************************************************************************/
- X
- X/** This is the built-in pager for displaying messages while in the Elm
- X program. It's a bare-bones pager with precious few options. The idea
- X is that those systems that are sufficiently slow that using an external
- X pager such as 'more' is too slow, then they can use this!
- X
- X Also added support for the "builtin+" pager (clears the screen for
- X each new page) including a two-line overlap for context...
- X
- X**/
- X
- X#include "headers.h"
- X#include <ctype.h>
- X
- X#define BEEP 007 /* ASCII Bell character */
- X
- Xstatic unfilled_lines,
- X form_title;
- X
- Xint lines_displayed, /* total number of lines displayed */
- X total_lines_to_display, /* total number of lines in message */
- X pages_displayed; /* for the nth page titles and all */
- X
- Xstart_builtin(lines_in_message)
- Xint lines_in_message;
- X{
- X /** clears the screen and resets the internal counters... **/
- X
- X dprint(8,(debugfile,
- X "displaying %d lines from message using internal pager\n",
- X lines_in_message));
- X
- X unfilled_lines = LINES;
- X form_title = 1;
- X lines_displayed = 0;
- X pages_displayed = 1;
- X
- X total_lines_to_display = lines_in_message;
- X}
- X
- Xextern int tabspacing;
- X
- Xint
- Xnext_line(inputptr, output, width)
- Xchar **inputptr, *output;
- Xregister unsigned width;
- X{
- X /* Copy characters from input to output and copy
- X * remainder of output to output. In copying use ^X notation for
- X * control characters, '?' non-ascii characters, expand tabs
- X * to correct number of spaces till next tab stop.
- X * Column zero of the next line is considered to be the tab stop
- X * that follows the last one that fits on a line.
- X * Copy until newline/return encountered, null char encountered,
- X * width characters producted in output buffer.
- X * Formfeed is handled exceptionally. If encountered it
- X * is removed from input and 1 is returned. Otherwise 0 is returned.
- X */
- X
- X register char *optr, *iptr;
- X register unsigned chars_output, nt;
- X int ret_val;
- X
- X optr = output;
- X iptr = *inputptr;
- X chars_output = 0;
- X
- X ret_val = 0; /* presume no formfeed */
- X while(1) {
- X
- X if(chars_output >= width) { /* no more room on line */
- X *optr++ = '\n';
- X *optr++ = '\r';
- X /* if next input character is newline or return,
- X * we can skip over it since we are outputing a newline anyway */
- X if((*iptr == '\n') || (*iptr == '\r'))
- X iptr++;
- X break;
- X } else if (*iptr == '\n' || *iptr == '\r') { /*newline or return */
- X *optr++ = '\n';
- X *optr++ = '\r';
- X iptr++;
- X break; /* end of line */
- X } else if(*iptr == '\f') { /* formfeed */
- X /* if next input character is newline or return,
- X * we can skip over it since we are outputing a formfeed anyway */
- X if((*++iptr == '\n') || (*iptr == '\r'))
- X iptr++;
- X ret_val = 1;
- X break; /* leave rest of screen clear */
- X } else if(*iptr == '\0') { /* none left in input string */
- X break;
- X } else if(!isascii(*iptr)) {
- X *optr++ = '?'; /* non ascii */
- X *iptr++;
- X chars_output++;
- X } else if(*iptr == '\t') { /* tab stop */
- X if((nt=next_tab(chars_output+1)) > width) {
- X *optr++ = '\n'; /* won't fit on this line - autowrap */
- X *optr++ = '\r'; /* tab by tabbing so-to-speak to 1st */
- X iptr++; /* column of next line */
- X break;
- X } else { /* will fit - output proper num of spaces */
- X while(chars_output < nt-1) {
- X chars_output++;
- X *optr++ = ' ';
- X }
- X iptr++;
- X }
- X } else if(isprint(*iptr)) {
- X *optr++ = *iptr++; /* printing character */
- X chars_output++;
- X } else { /* non-white space control character */
- X if(chars_output + 2 <= width) {
- X *optr++ = '^';
- X *optr++ = (*iptr == '\177' ? '?' : *iptr + 'A' - 1);
- X iptr++;
- X chars_output += 2;
- X } else { /* no space on line for both chars */
- X break;
- X }
- X }
- X }
- X *optr = '\0';
- X *inputptr = iptr;
- X return(ret_val);
- X}
- X
- X
- Xint
- Xdisplay_line(input_line)
- Xchar *input_line;
- X{
- X /** Display the given line on the screen, taking into account such
- X dumbness as wraparound and such. If displaying this would put
- X us at the end of the screen, put out the "MORE" prompt and wait
- X for some input. Return non-zero if the user terminates the
- X paging (e.g. 'i') or zero if we should continue. Also,
- X this will pass back the value of any character the user types in
- X at the prompt instead, if needed... (e.g. if it can't deal with
- X it at this point)
- X **/
- X
- X char *pending, footer[SLEN], display_buffer[SLEN], ch;
- X int formfeed;
- X
- X pending = input_line;
- X CarriageReturn();
- X
- X do {
- X
- X /* while there is more space on the screen - leave prompt line free */
- X while(unfilled_lines > 0) {
- X
- X /* display a screen's lineful of the input line
- X * and reset pending to point to remainder of input line */
- X formfeed = next_line(&pending, display_buffer, COLUMNS);
- X
- X if(*display_buffer == '\0') { /* no line to display */
- X if(!formfeed) /* no "formfeed" to display
- X * need more lines for screen */
- X return(FALSE);
- X } else
- X Write_to_screen(display_buffer, 0);
- X
- X /* if formfeed, clear remainder of screen */
- X if(formfeed) {
- X CleartoEOS();
- X unfilled_lines=0;
- X }
- X else
- X unfilled_lines--;
- X
- X /* if screen is not full (leave room for prompt)
- X * but we've used up input line, return */
- X
- X if(unfilled_lines > 0 && *pending == '\0')
- X return(FALSE); /* we need more lines to fill screen */
- X
- X /* otherwise continue to display next part of input line */
- X }
- X
- X /* screen is now full - prompt for user input */
- X sprintf(footer,
- X ( (user_level == 0) ?
- X " There %s %d line%s left (%d%%). Press <space> for more, or 'i' to return. "
- X : (user_level == 1) ?
- X " %s%d line%s more (%d%%). Press <space> for more, 'i' to return. "
- X :
- X " %s%d line%s more (you've seen %d%%) "),
- X (user_level == 0 ?
- X (total_lines_to_display - lines_displayed == 1 ?
- X "is" : "are") : ""),
- X total_lines_to_display - lines_displayed,
- X plural(total_lines_to_display - lines_displayed),
- X (int)((100L * lines_displayed) / total_lines_to_display));
- X
- X MoveCursor(LINES, 0);
- X StartBold();
- X Write_to_screen(footer, 0);
- X EndBold();
- X
- X switch(ch = ReadCh()) {
- X
- X case '\n':
- X case '\r': /* scroll down a line */
- X unfilled_lines = 1;
- X ClearLine(LINES);
- X break;
- X
- X case ' ': /* scroll a screenful */
- X unfilled_lines = LINES;
- X if(clear_pages) {
- X ClearScreen();
- X MoveCursor(0,0);
- X CarriageReturn();
- X
- X /* output title */
- X if(title_messages && filter) {
- X title_for_page(++pages_displayed);
- X unfilled_lines -= 2;
- X }
- X } else ClearLine(LINES);
- X
- X /* and keep last line to be first line of next
- X * screenful unless we had a formfeed */
- X if(!formfeed) {
- X if(clear_pages)
- X Write_to_screen(display_buffer, 0);
- X unfilled_lines--;
- X }
- X break;
- X
- X default: return(ch);
- X }
- X CarriageReturn();
- X } while(*pending);
- X return(FALSE);
- X}
- X
- Xtitle_for_page(page)
- Xint page;
- X{
- X /** Output a nice title for the second thru last pages of the message
- X we're currently reading. Note - this code is very similar to
- X that which produces the title for the first page, except that
- X page number replaces the date and the method by which it
- X gets to the screen **/
- X
- X static char title1[SLEN], title2[SLEN];
- X char titlebuf[SLEN], title3[SLEN], who[SLEN];
- X static t1_len, t2_len;
- X register int padding, showing_to;
- X
- X /* format those parts of the title that are constant for a message */
- X if(form_title) {
- X
- X showing_to = tail_of(headers[current-1]->from, who,
- X headers[current-1]->to);
- X
- X sprintf(title1, "%s %d/%d ",
- X headers[current-1]->status & DELETED ? "[deleted]" :
- X headers[current-1]->status & FORM_LETTER ? "Form": "Message",
- X current, message_count);
- X t1_len = strlen(title1);
- X sprintf(title2, "%s %s", showing_to? "To" : "From", who);
- X t2_len = strlen(title2);
- X }
- X /* format those parts of the title that vary between pages of a mesg */
- X sprintf(title3, " Page %d", page);
- X
- X /* truncate or pad title2 portion on the right
- X * so that line fits exactly to the rightmost column */
- SHAR_EOF
- echo "End of part 11"
- echo "File src/builtin.c is continued in part 12"
- echo "12" > s2_seq_.tmp
- exit 0
-
-